package com.yunshipei.core.manager;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;

import com.yunshipei.core.R;
import com.yunshipei.core.common.ContentValues;
import com.yunshipei.core.common.XCloudException;
import com.yunshipei.core.model.AdapterApplication;
import com.yunshipei.core.model.ConfigInfo;
import com.yunshipei.core.model.UWAApplication;
import com.yunshipei.core.net.EnterClient;
import com.yunshipei.core.net.ServiceApi;
import com.yunshipei.core.net.convert.JsonConverterFactory;
import com.yunshipei.core.utils.FileUtils;
import com.yunshipei.core.utils.StringUtils;
import com.yunshipei.core.utils.YspLogUtils;

import org.chromiun.net.GURLUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.reactivestreams.Publisher;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import io.reactivex.Flowable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

import static com.yunshipei.core.common.ContentValues.MANAGER_VERSION;

class DataConfiguration {

    private Context mContext;

    private JSONObject mLoginJSONObject;
    private SharedPreferences mPreferences;
    private String mAppFilePath;
    private String mManagerServer;

    private boolean isFromCache = false;


    DataConfiguration(Context context, String managerServer, JSONObject mLoginJSONObject) {
        this.mContext = context;
        this.mManagerServer = managerServer;
        this.mLoginJSONObject = mLoginJSONObject;
        this.mAppFilePath = mContext.getFilesDir().getPath();
        this.mPreferences = mContext.getSharedPreferences(XCloudSDKManager.SP_CONFIG_FILE_NAME, Context.MODE_PRIVATE);
    }

    DataConfiguration(Context context, String managerServer, JSONObject mLoginJSONObject, boolean fromCache) {
        this(context, managerServer, mLoginJSONObject);
        this.isFromCache = fromCache;
    }

    public Flowable<JSONObject> config() throws Exception {
        int status = mLoginJSONObject.optInt("status", 0);
        if (0 == status) {
            return Flowable.error(new XCloudException(mLoginJSONObject.optString("message", mContext.getString(R.string.login_interface_error_no_msg))));
        }
        JSONObject data = mLoginJSONObject.optJSONObject("data");
        if (data == null) {
            return Flowable.error(new XCloudException(mContext.getString(R.string.login_interface_no_data)));
        }
        int managerCode = data.optInt("managerCode", -1);
        if (managerCode >= 1) {
            return configXCloud2Map();
        } else {
            return new XCloudDataHandler(mContext, mManagerServer, mLoginJSONObject, isFromCache).start().doOnNext(new Consumer<JSONObject>() {
                @Override
                public void accept(JSONObject jsonObject) throws Exception {
                    mPreferences.edit().putInt(MANAGER_VERSION, 0).apply();
                }
            });
        }
    }

    //登录不在下载适配包和运行时，需要清除以前旧逻辑的适配包和运行时，并且需要清空适配包运行时的配置信息
    @SuppressLint("ApplySharedPref")
    private Flowable<JSONObject> configXCloud2Map() throws JSONException {
        //为了兼容客户端从旧版服务器登录过渡到新版服务器登录或者从新版服务器登录过渡到旧版服务器登录这两种情况，需要判断上一次登录使用的是旧版服务器登录还是新版服务器登录
        int managerCode = mPreferences.getInt(MANAGER_VERSION, 0);
        if (managerCode < 1) {
            //删除适配包以及适配包和运行时保存的配置信息(运行时不删除，因为运行时的版本信息依赖于运行时文件夹)
            String adapterPakPath = mAppFilePath + File.separator + ContentValues.APP_WEB_ROOT_PATH + File.separator + ContentValues.YSP_NEW_ADAPTER_PAC_PATH;
            FileUtils.deleteFileHoldPath(adapterPakPath);
            mPreferences.edit().putString(XCloudDataHandler.SP_KEY_ADAPTER_PKG_CONFIG_NAME, "").putString(XCloudDataHandler.SP_KEY_LAST_OLD_HOME_PAGE_VERSION, "").commit();
        }
        JSONObject dataObject = mLoginJSONObject.optJSONObject("data");
        mPreferences.edit().putInt(MANAGER_VERSION, dataObject.optInt("managerCode", 0)).apply();
        JSONObject companyJSONObject = dataObject.optJSONObject("company");
        if (companyJSONObject == null) {
            return Flowable.error(new XCloudException("company字段为null"));
        }
        //解析运行时解密所需字段内容
        String companyId = companyJSONObject.optString("companyId");
        String created = companyJSONObject.optString("created");
        String encManagerServer = companyJSONObject.optString("managerServer");
        boolean privateDeployment = companyJSONObject.optBoolean("privateDeployment");
        String webSite = companyJSONObject.optString("website");
        String encDataStr = new JSONObject().put("filepath", mAppFilePath + File.separator).put("_id", companyId).put("created", created).put("managerServer", encManagerServer).put("privateDeployment", privateDeployment).put("website", webSite).toString();
        mPreferences.edit().putString(XCloudDataHandler.SP_KEY_RUNTIME_ENC_CONFIG_NAME, encDataStr).commit();
        //解析SDK中适配心跳校验数据
        String token = dataObject.optString("deviceToken", "");
        final int validCount = dataObject.optInt("validCount", 0);
        long timestamp = dataObject.optLong("timestamp", 0);
        String sdkSum = dataObject.optString("sdk_sum", "");
        String uuid = dataObject.optString("uuid", "");
        if (!isFromCache) {
            //如果是登录出错加载缓存，则一定会校验失败
            if (!TextUtils.isEmpty(token) && !TextUtils.isEmpty(sdkSum) && !TextUtils.isEmpty(uuid) && validCount != 0 && timestamp != 0) {
                String sdkSumStr = new JSONObject().put("token", token).put("count", validCount).put("timestamp", timestamp).put("sdk_sum", sdkSum).put("deviceId", uuid).toString();
                String checkSum = GURLUtils.checkSum(sdkSumStr);
                if (TextUtils.isEmpty(checkSum) || !"check success".equalsIgnoreCase(checkSum)) {
                    return Flowable.error(new XCloudException("sdkSum check failed：" + checkSum));
                }
                YspLogUtils.d("checkSum status:" + checkSum);
            }
        }
        //适配配置信息
        List<String> logs = new ArrayList<>();
        JSONArray logArray = companyJSONObject.optJSONArray("logs");
        if (logArray != null && logArray.length() > 0) {
            int len = logArray.length();
            for (int i = 0; i < len; i++) {
                String str = logArray.optString(i);
                if (!TextUtils.isEmpty(str)) {
                    logs.add(str);
                }
            }
        }
        final ConfigInfo configInfo = new ConfigInfo(companyId, token, uuid, mManagerServer, logs, encManagerServer);
        configInfo.setDownloadRuntimeFromManager(companyJSONObject.optBoolean("useManager", false));
        configInfo.setCompanyName(webSite);
        //解析所有的适配包的信息
        JSONArray adapterPkgJSONArray = null;
        JSONArray uwaPkgApplications = null;
        final JSONObject dataJSObject = dataObject.optJSONObject("datajsApps");
        if (dataJSObject != null) {
            JSONObject incrementalVersionsJSONObject = dataJSObject.optJSONObject("incrementalVersions");
            if (incrementalVersionsJSONObject != null) {
                adapterPkgJSONArray = incrementalVersionsJSONObject.optJSONArray("applications");
                uwaPkgApplications = incrementalVersionsJSONObject.optJSONArray("universalWebApps");
            }
        }
        final List<AdapterApplication> adapterApplications = new ArrayList<>();
        if (adapterPkgJSONArray != null) {
            int len = adapterPkgJSONArray.length();
            for (int i = 0; i < len; i++) {
                JSONObject adapterPkgObject = adapterPkgJSONArray.optJSONObject(i);
                String downloadUrl = adapterPkgObject.optString("downloadUrl", "");
                String appId = adapterPkgObject.optString("appId", "");
                String version = adapterPkgObject.optString("version", "");
                if (!TextUtils.isEmpty(downloadUrl) && !TextUtils.isEmpty(appId) && !TextUtils.isEmpty(version)) {
                    AdapterApplication adapterApplication = new AdapterApplication(downloadUrl, appId, version);
                    adapterApplications.add(adapterApplication);
                }
            }
        }
        configInfo.setAdapterApplications(adapterApplications);
        List<UWAApplication> uwaApplications = new ArrayList<>();
        if (uwaPkgApplications != null) {
            int len = uwaPkgApplications.length();
            for (int i = 0; i < len; i++) {
                JSONObject uwaJSONObject = uwaPkgApplications.optJSONObject(i);
                String downloadUrl = uwaJSONObject.optString("downloadUrl", "");
                String appId = uwaJSONObject.optString("appId", "");
                String version = uwaJSONObject.optString("version", "");
                if (!TextUtils.isEmpty(downloadUrl) && !TextUtils.isEmpty(appId) && !TextUtils.isEmpty(version)) {
                    UWAApplication uwaApplication = new UWAApplication(downloadUrl, appId, version);
                    uwaApplications.add(uwaApplication);
                }
            }
        }
        configInfo.setUWAApplications(uwaApplications);
        //删除接口没有，但本地存在的多余适配包和小程序包
        new LocalPackageManager(mContext, adapterApplications, uwaApplications).updateLocalApps();
        if (!isFromCache) {
            OkHttpClient okHttpClient = EnterClient.getInstances().getManagerClient();
            ServiceApi serviceApi = new Retrofit.Builder().client(okHttpClient).baseUrl(mManagerServer).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).addConverterFactory(JsonConverterFactory.create()).build().create(ServiceApi.class);
            return serviceApi.allManifest(companyId, uuid).flatMap(new Function<JSONObject, Publisher<JSONArray>>() {
                @Override
                public Publisher<JSONArray> apply(JSONObject jsonObject) throws Exception {
                    YspLogUtils.d("manifest：" + jsonObject.toString());
                    int status = jsonObject.optInt("status", 0);
                    if (1 == status) {
                        JSONArray data = jsonObject.optJSONArray("data");
                        if (data == null) {
                            data = new JSONArray("[]");
                        } else {
                            List<String> appScops = new ArrayList<>();
                            for (AdapterApplication adapterApplication : adapterApplications) {
                                String scope = StringUtils.getZipPkgDownloadUrlFileName(adapterApplication.getDownloadUrl());
                                if (!TextUtils.isEmpty(scope)) {
                                    appScops.add(scope);
                                }
                            }
                            JSONArray filterJSONArray = new JSONArray();
                            for (int i = 0; i < data.length(); i++) {
                                JSONObject dataObject = data.optJSONObject(i);
                                if (dataObject != null) {
                                    String tempScope = dataObject.optString("scope");
                                    if (!TextUtils.isEmpty(tempScope) && appScops.contains(tempScope)) {
                                        filterJSONArray.put(dataObject);
                                    }
                                }
                            }
                            data = filterJSONArray;
                        }
                        return Flowable.just(data);
                    }
                    return Flowable.error(new XCloudException(jsonObject.optString("message", mContext.getString(R.string.no_error_msg_interface))));
                }
            }).flatMap(new Function<JSONArray, Publisher<JSONObject>>() {
                @Override
                public Publisher<JSONObject> apply(JSONArray jsonArray) throws Exception {
                    XCloud2Map.getInstance().init(configInfo, validCount, mAppFilePath, jsonArray);
                    return Flowable.just(mLoginJSONObject);
                }
            });
        } else {
            XCloud2Map.getInstance().init(configInfo, validCount, mAppFilePath, null);
            return Flowable.just(mLoginJSONObject);
        }
    }
}
